﻿#include "stdafx.h"
#include "RenderSceneModels.h"
#include "Terrain.h"


RenderSceneModels::RenderSceneModels()
{
	//m_renders = nullptr;
	//m_animate = nullptr;
}


RenderSceneModels::~RenderSceneModels()
{
	Clear();
}

void RenderSceneModels::Init(Camera *camera, Shader *shader, Terrain *terrain)
{
	m_camera = camera;
	m_shader = shader;
	m_terrain = terrain;
}

void RenderSceneModels::Clear()
{
	m_boundBoxObjs.clear();
	for (auto &obj : m_skelAnimObjs)
	{
		if (obj)
		{
			delete obj;
			obj = nullptr;
		}
	}
	//if (m_renders)
	//{
	//	delete[] m_renders;
	//	m_renders = nullptr;
	//}
	//if (m_animate)
	//{
	//	delete[] m_animate;
	//	m_animate = nullptr;
	//}

	for (int y = 0; y < 256; y++)
	{
		for (int x = 0; x < 256; x++)
		{
			m_drawInfos[y][x].clear();
		}
	}
}

void RenderSceneModels::Load(int index)
{
	bool fok;
	Clear();
	m_mdls_load.Load(index);
	int count = m_mdls_load.m_models.size();
	m_skelAnimObjs.resize(count);
	//Render *rend = m_renders = new Render[count];//要求修改,把m_renders声明成指针的指针，不需要new出这么多实体
	//m_animate = new Animate[count];
	//Animate *anim = m_animate;
	auto &mdls = m_mdls_load.m_models;
	for (int i = 0; i < count; i++)
	{
		if ((index == 0) && (i == Models_scene_object1_PoseBox01_index)) continue;
		if (mdls[i])
		{
			m_skelAnimObjs[i] = new SkeletonAnimation(m_camera, mdls[i], m_shader);
			//rend->SetMesh(&mdls[i]->m_vaoMesh, mdls[i]->m_materials, m_shader);
			//anim->SetAnimData(&mdls[i]->m_animationData);
		}
		//else m_skelAnimObjs[i] = nullptr;
		//rend++;
		//anim++;
	}
	char fileName[300];
	sprintf(fileName, "./Data/World%d/%s", index + 1, "Terrain.obj");
	fok = ReadTerrainObj(fileName);
}


void RenderSceneModels::UpdateArea(glm::ivec4 &drawArea)
{
	m_drawArea = drawArea;
	m_drawList.clear();
	m_boundBoxObjs.clear();
	//将obj按render指针分类
	auto addObj = [&](DrawObjInfo *obj)
	{
		for (auto &ds : m_drawList)
		{
			if (ds[0]->index == obj->index)
			{
				ds.push_back(obj);
				return;
			}
		}
		m_drawList.push_back(std::vector<DrawObjInfo*>());
		m_drawList.back().push_back(obj);
	};

	int x2 = m_drawArea.x + m_drawArea.z;
	int y2 = m_drawArea.y + m_drawArea.w;
	for (int y = m_drawArea.y; y < y2; y++)
		for (int x = m_drawArea.x; x < x2; x++)
			for (auto &obj : m_drawInfos[y][x])
			{
				if (obj.index == Models_scene_object1_PoseBox01_index)
				{
					//int count = m_boundBoxObjs.size();
					PoseBoundBox poseBox;
					//poseBox.obj = this;
					poseBox.m_drawParam.bdMin = glm::vec4(m_mdls_load.m_boundingBoxMin, 1.0f);
					poseBox.m_drawParam.bdMax = glm::vec4(m_mdls_load.m_boundingBoxMax, 1.0f);
					poseBox.trans = &obj.trans;
					poseBox.position = glm::ivec2(obj.trans[3]);
					poseBox.position /= 100;
					m_boundBoxObjs.push_back(poseBox);
					//m_boundBoxObjs.push_back(m_skelAnimObjs[Models_scene_object1_PoseBox01_index]);
				}
				else addObj(&obj);
			}
}

void RenderSceneModels::Draw()
{
	DrawInstParams drawParam;

	Shaders::GetInstance()->m_uboMaterial.UseLight(2, true);
	auto &ubo = Shaders::GetInstance()->m_uboDrawInst;
	double dt = FrameTime::GetInstance()->GetDeltaTime();
	glm::mat4 *mats;
	int nInst;
	int count;
	int maxInst = Shaders::GetInstance()->max_uboDrawInst;
	for (auto &list : m_drawList)
	{
		int index = list[0]->index;
		Render *r = m_skelAnimObjs[index]->GetRender(0);
		Animate *a = &m_skelAnimObjs[index]->m_animate;
		a->Update(dt);
		int nmat = a->GetBoneTransformMatrixs(&mats);
		Shaders::GetInstance()->m_uBoneTransformMatrix.SetBufferData(0, sizeof(glm::mat4)*nmat, mats, true);
		count = 0;
		ubo.Bind();
		for (auto obj : list)
		{
			drawParam.Mvp = m_camera->GetViewProjectionMatrix() * obj->trans;
			drawParam.ProjectionMatrix = m_camera->GetProjectionMatrix();
			drawParam.ModelViewMatrix = m_camera->GetViewMatrix() * obj->trans;
			drawParam.NormalMatrix = &glm::inverseTranspose(glm::mat3(drawParam.ModelViewMatrix))[0][0];
			memcpy(&drawParam.Color, obj->color, 16);
			ubo.SetBufferData(count * sizeof(DrawInstParams), sizeof(DrawInstParams), &drawParam, false);
			count++;
			if (count == maxInst)
			{
				r->Draw(count);
				count = 0;
			}
		}
		if (count) r->Draw(count);
	}

	auto &fbo = Shaders::GetInstance()->m_fboColorPick;
	count = GetBoundBoxCount();
	for (int i = 0; i < count; i++)
	{
		fbo.Add(GetBoundBox(i));
	}
}

//读取Terrain.obj文件，把渲染对象根据位置填充到 m_drawInfos（256*256）
bool RenderSceneModels::ReadTerrainObj(char *fileName)
{
	FILE *fp = fopen(fileName, "rb");
	if (!fp) return false;;
	long flen;
	BYTE *pdata;
	WORD objCount;
	TerrainObjInfo *pobjInfo;
	DrawObjInfo dobjInfo;

	fseek(fp, 0, SEEK_END);
	flen = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	pdata = new BYTE[flen];
	fread(pdata, flen, 1, fp);
	fclose(fp);
	objCount = *(WORD*)(pdata + 1);
	pobjInfo = (TerrainObjInfo*)(pdata + 3);

	for (int y = 0; y < 256; y++)
		for (int x = 0; x < 256; x++)
		{
			m_drawInfos[y][x].clear();
		}
	int x, y;
	BYTE *color;
	for (int i = 0; i < objCount; i++)
	{
		x = (int)pobjInfo->position[0] / 100;
		y = (int)pobjInfo->position[1] / 100;
		if (x < 0) x = 0;
		else if (x>255) x = 255;
		if (y < 0) y = 0;
		else if (y>255) y = 255;
		dobjInfo.index = pobjInfo->index;
		//dobjInfo.render = m_renders + pobjInfo->index;
		//dobjInfo.animate = m_animate + pobjInfo->index;

		glm::mat4 Model = glm::translate(glm::mat4(1.0f), glm::make_vec3(pobjInfo->position));
		if (pobjInfo->rotate[0] != 0.0f) Model = glm::rotate<float>(Model, glm::radians(pobjInfo->rotate[0]), glm::vec3(1, 0, 0));
		if (pobjInfo->rotate[1] != 0.0f) Model = glm::rotate<float>(Model, glm::radians(pobjInfo->rotate[1]), glm::vec3(0, 1, 0));
		if (pobjInfo->rotate[2] != 0.0f) Model = glm::rotate<float>(Model, glm::radians(pobjInfo->rotate[2]), glm::vec3(0, 0, 1));
		dobjInfo.trans = glm::scale(Model, glm::vec3(pobjInfo->scale));

		m_terrain->GetColor(x, y, dobjInfo.color);
		dobjInfo.color[3] = 1.0f;
		m_drawInfos[y][x].push_back(dobjInfo);
		pobjInfo++;
	}
	delete pdata;
	return true;
}

void RenderSceneModels::OnFocus(bool focus)
{

}

void RenderSceneModels::OnSelect(bool select)
{

}

BoundBoxObject *RenderSceneModels::GetBoundBox(int index)
{
	auto &box = m_boundBoxObjs[index];
	box.m_drawParam.Mvp = m_camera->GetViewProjectionMatrix() * (*box.trans);
	return &box;
}

int RenderSceneModels::GetBoundBoxCount()
{
	return m_boundBoxObjs.size();
}
//void RenderSceneModels::BoundBox::OnFocus(bool focus)
//{
//	obj->OnFocus(focus);
//}
//
//void RenderSceneModels::BoundBox::OnSelect(bool select)
//{
//	obj->OnSelect(select);
//}
